home *** CD-ROM | disk | FTP | other *** search
- /* SC A Spreadsheet Calculator
-
- * Expression interpreter and assorted support routines.
-
- *
-
- * original by James Gosling, September 1982
-
- * modified by Mark Weiser and Bruce Israel,
-
- * University of Maryland
-
- *
-
- * More mods Robert Bond, 12/86
-
- * Major mods to run on VMS and AMIGA, 1/17/87
-
- */
-
-
-
- #include "sc.h"
-
- #define DEFCOLDELIM ':'
-
-
-
- char *malloc();
-
-
-
- double dosum(minr, minc, maxr, maxc)
-
- int minr, minc, maxr, maxc;
-
- {
-
- double v;
-
- register r,c;
-
- register struct ent *p;
-
-
-
- v = 0;
-
- for (r = minr; r<=maxr; r++)
-
- for (c = minc; c<=maxc; c++)
-
- if ((p = tbl[r][c]) && p->flags&is_valid)
-
- v += p->v;
-
- return v;
-
- }
-
-
-
- double doprod(minr, minc, maxr, maxc)
-
- int minr, minc, maxr, maxc;
-
- {
-
- double v;
-
- register r,c;
-
- register struct ent *p;
-
-
-
- v = 1;
-
- for (r = minr; r<=maxr; r++)
-
- for (c = minc; c<=maxc; c++)
-
- if ((p = tbl[r][c]) && p->flags&is_valid)
-
- v *= p->v;
-
- return v;
-
- }
-
-
-
- double doavg(minr, minc, maxr, maxc)
-
- int minr, minc, maxr, maxc;
-
- {
-
- double v;
-
- register r,c,count;
-
- register struct ent *p;
-
-
-
- v = 0;
-
- count = 0;
-
- for (r = minr; r<=maxr; r++)
-
- for (c = minc; c<=maxc; c++)
-
- if ((p = tbl[r][c]) && p->flags&is_valid) {
-
- v += p->v;
-
- count++;
-
- }
-
-
-
- return (v / (double)count);
-
- }
-
-
-
- double eval(e)
-
- register struct enode *e; {
-
- if (e==0) return 0;
-
- switch (e->op) {
-
- case '+': return (eval(e->e.o.left) + eval(e->e.o.right));
-
- case '-': return (eval(e->e.o.left) - eval(e->e.o.right));
-
- case '*': return (eval(e->e.o.left) * eval(e->e.o.right));
-
- case '/': { double denom = eval (e->e.o.right);
-
- return denom ? eval(e->e.o.left) / denom : 0; }
-
- case '<': return (eval(e->e.o.left) < eval(e->e.o.right));
-
- case '=': return (eval(e->e.o.left) == eval(e->e.o.right));
-
- case '>': return (eval(e->e.o.left) > eval(e->e.o.right));
-
- case '&': return (eval(e->e.o.left) != 0.0 &&
-
- eval(e->e.o.right) != 0.0) ? 1.0 : 0.0;
-
- case '|': return (eval(e->e.o.left) != 0.0 ||
-
- eval(e->e.o.right) != 0.0) ? 1.0 : 0.0;
-
- case '?': return eval(e->e.o.left) ? eval(e->e.o.right->e.o.left)
-
- : eval(e->e.o.right->e.o.right);
-
- case 'm': return (-eval(e->e.o.right));
-
- case 'f': return (eval(e->e.o.right));
-
- case '~': return (!eval(e->e.o.right));
-
- case 'k': return (e->e.k);
-
- case 'v': return (e->e.v->v);
-
- case O_REDUCE('+'):
-
- case O_REDUCE('*'):
-
- case O_REDUCE('a'):
-
- {
-
- #ifdef TOS
-
- register r,c;
-
- int maxr, maxc;
-
- int minr, minc;
-
- #else
-
- register r,c;
-
- register maxr, maxc;
-
- register minr, minc;
-
- #endif
-
- maxr = ((struct ent *) e->e.o.right) -> row;
-
- maxc = ((struct ent *) e->e.o.right) -> col;
-
- minr = ((struct ent *) e->e.o.left) -> row;
-
- minc = ((struct ent *) e->e.o.left) -> col;
-
- if (minr>maxr) r = maxr, maxr = minr, minr = r;
-
- if (minc>maxc) c = maxc, maxc = minc, minc = c;
-
- switch (e->op) {
-
- case O_REDUCE('+'): return dosum(minr, minc, maxr, maxc);
-
- case O_REDUCE('*'): return doprod(minr, minc, maxr, maxc);
-
- case O_REDUCE('a'): return doavg(minr, minc, maxr, maxc);
-
- }
-
- }
-
- }
-
- }
-
-
-
- #define MAXPROP 7
-
-
-
- EvalAll () {
-
- int lastct,repct = 0;
-
-
-
- while ((lastct = RealEvalAll()) && (repct++ <= MAXPROP));
-
-
-
- repct--;
-
- }
-
-
-
- int RealEvalAll () {
-
- register i,j;
-
- int chgct = 0;
-
- register struct ent *p;
-
- for (i=0; i<=maxrow; i++)
-
- for (j=0; j<=maxcol; j++)
-
- if ((p=tbl[i][j]) && p->expr) {
-
- double v = eval (p->expr);
-
- if (v != p->v) {
-
- p->v = v; chgct++;
-
- p->flags |= (is_changed|is_valid);
-
- }
-
- }
-
- return(chgct);
-
- }
-
-
-
- struct enode *new(op,a1,a2)
-
- struct enode *a1, *a2; {
-
- register struct enode *p = (struct enode *) malloc (sizeof (struct enode));
-
- p->op = op;
-
- switch (op) {
-
- case O_VAR: p->e.v = (struct ent *) a1; break;
-
- case O_CONST: p->e.k = *(double *)&a1; break;
-
- default: p->e.o.left = a1; p->e.o.right = a2;
-
- }
-
- return p;
-
- }
-
-
-
- copy (dv, v1, v2)
-
- struct ent *dv, *v1, *v2;
-
- {
-
- register r,c;
-
- register struct ent *p;
-
- register struct ent *n;
-
- register deltar, deltac;
-
- int maxr, maxc;
-
- int minr, minc;
-
- int dr, dc;
-
-
-
- dr = dv->row;
-
- dc = dv->col;
-
- maxr = v2->row;
-
- maxc = v2->col;
-
- minr = v1->row;
-
- minc = v1->col;
-
- if (minr>maxr) r = maxr, maxr = minr, minr = r;
-
- if (minc>maxc) c = maxc, maxc = minc, minc = c;
-
- if (dr+maxr-minr >= MAXROWS ||
-
- dc+maxc-minc >= MAXCOLS) {
-
- error ("The table can't be any bigger");
-
- return;
-
- }
-
- deltar = dr-minr;
-
- deltac = dc-minc;
-
- FullUpdate++;
-
- for (r = minr; r<=maxr; r++)
-
- for (c = minc; c<=maxc; c++) {
-
- n = lookat (r+deltar, c+deltac);
-
- clearent(n);
-
- if (p = tbl[r][c]) {
-
- n -> v = p -> v;
-
- n -> flags = p -> flags;
-
- n -> expr = copye(p->expr, deltar, deltac);
-
- n -> label = 0;
-
- if (p -> label) {
-
- n -> label = (char *)
-
- malloc (strlen (p -> label) + 1);
-
- strcpy (n -> label, p -> label);
-
- }
-
- }
-
- }
-
- }
-
-
-
- let (v, e)
-
- struct ent *v;
-
- struct enode *e; {
-
- efree (v->expr);
-
- if (constant(e)) {
-
- v->v = eval(e);
-
- v->expr = 0;
-
- efree(e);
-
- } else
-
- v->expr = e;
-
- v->flags |= (is_changed|is_valid);
-
- changed++;
-
- modflg++;
-
- }
-
-
-
- clearent (v)
-
- struct ent *v; {
-
- if (!v)
-
- return;
-
- label(v,"",-1);
-
- v->v = 0;
-
- if (v->expr)
-
- efree(v->expr);
-
- v->expr = 0;
-
- v->flags |= (is_changed);
-
- v->flags &= ~(is_valid);
-
- changed++;
-
- modflg++;
-
- }
-
-
-
- constant(e)
-
- register struct enode *e; {
-
- return e==0 || e->op == O_CONST
-
- || (e->op != O_VAR
-
- && (e->op&~0177) != O_REDUCE(0)
-
- && constant (e->e.o.left)
-
- && constant(e->e.o.right));
-
- }
-
-
-
- efree (e)
-
- register struct enode *e; {
-
- if (e) {
-
- if (e->op != O_VAR && e->op !=O_CONST && (e->op&~0177) != O_REDUCE(0)) {
-
- efree (e->e.o.left);
-
- efree (e->e.o.right);
-
- }
-
- free (e);
-
- }
-
- }
-
-
-
- label (v, s, flushdir)
-
- register struct ent *v;
-
- register char *s; {
-
- if (v) {
-
- if (flushdir==0 && v->flags&is_valid) {
-
- register struct ent *tv;
-
- if (v->col>0 && ((tv=lookat(v->row,v->col-1))->flags&is_valid)==0)
-
- v = tv, flushdir = 1;
-
- else if (((tv=lookat (v->row,v->col+1))->flags&is_valid)==0)
-
- v = tv, flushdir = -1;
-
- else flushdir = -1;
-
- }
-
- if (v->label) free(v->label);
-
- if (s && s[0]) {
-
- v->label = (char *) malloc (strlen(s)+1);
-
- strcpy (v->label, s);
-
- } else v->label = 0;
-
- v->flags |= is_lchanged;
-
- if (flushdir<0) v->flags |= is_leftflush;
-
- else v->flags &= ~is_leftflush;
-
- FullUpdate++;
-
- modflg++;
-
- }
-
- }
-
-
-
- decodev (v)
-
- register struct ent *v; {
-
- if (v) sprintf (line+linelim, "%s%d", coltoa(v->col), v->row);
-
- else sprintf (line+linelim,"VAR?");
-
- linelim += strlen (line+linelim);
-
- }
-
-
-
- char *
-
- coltoa(col)
-
- int col;
-
- {
-
- static char rname[3];
-
- register char *p = rname;
-
-
-
- if (col < 0 || col > 25*26)
-
- debug("coltoa: invalid col: %d", col);
-
-
-
- if (col > 25) {
-
- *p++ = col/26 + 'A' - 1;
-
- col %= 26;
-
- }
-
- *p++ = col+'A';
-
- *p = 0;
-
- return(rname);
-
- }
-
-
-
- decompile(e, priority)
-
- register struct enode *e; {
-
- register char *s;
-
- if (e) {
-
- int mypriority;
-
- switch (e->op) {
-
- default: mypriority = 99; break;
-
- case '?': mypriority = 1; break;
-
- case ':': mypriority = 2; break;
-
- case '|': mypriority = 3; break;
-
- case '&': mypriority = 4; break;
-
- case '<': case '=': case '>': mypriority = 6; break;
-
- case '+': case '-': mypriority = 8; break;
-
- case '*': case '/': mypriority = 10; break;
-
- }
-
- if (mypriority<priority) line[linelim++] = '(';
-
- switch (e->op) {
-
- case 'f': {
-
- for (s="fixed "; line[linelim++] = *s++;);
-
- linelim--;
-
- decompile (e->e.o.right, 30);
-
- break;
-
- }
-
- case 'm': line[linelim++] = '-';
-
- decompile (e->e.o.right, 30);
-
- break;
-
- case '~': line[linelim++] = '~';
-
- decompile (e->e.o.right, 30);
-
- break;
-
- case 'v': decodev (e->e.v);
-
- break;
-
- case 'k': sprintf (line+linelim,"%.8g",e->e.k);
-
- linelim += strlen (line+linelim);
-
- break;
-
- case O_REDUCE('+'):
-
- for (s="@sum("; line[linelim++] = *s++;);
-
- goto more;
-
- case O_REDUCE('*'):
-
- for (s="@prod("; line[linelim++] = *s++;);
-
- goto more;
-
- case O_REDUCE('a'):
-
- for (s="@avg("; line[linelim++] = *s++;);
-
- more: linelim--;
-
- decodev (e->e.o.left);
-
- line[linelim++] = ':';
-
- decodev (e->e.o.right);
-
- line[linelim++] = ')';
-
- break;
-
-
-
- default: decompile (e->e.o.left, mypriority);
-
- line[linelim++] = e->op;
-
- decompile (e->e.o.right, mypriority+1);
-
- break;
-
- }
-
- if (mypriority<priority) line[linelim++] = ')';
-
- } else line[linelim++] = '?';
-
- }
-
-
-
- editv (row, col) {
-
- sprintf (line, "let %s%d = ", coltoa(col), row);
-
- linelim = strlen(line);
-
- editexp(row,col);
-
- }
-
-
-
- editexp(row,col) {
-
- register struct ent *p;
-
- p = lookat (row, col);
-
- if (p->flags&is_valid)
-
- if (p->expr) {
-
- decompile (p->expr);
-
- line[linelim] = 0;
-
- } else {
-
- sprintf (line+linelim, "%.8g", p->v);
-
- linelim += strlen (line+linelim);
-
- }
-
- }
-
-
-
- edits (row, col) {
-
- register struct ent *p = lookat (row, col);
-
- sprintf (line, "%sstring %s%d = \"",
-
- ((p->flags&is_leftflush) ? "left" : "right"),
-
- coltoa(col), row);
-
- linelim = strlen(line);
-
- sprintf (line+linelim, "%s", p->label);
-
- linelim += strlen (line+linelim);
-
- }
-
-
-
- printfile (fname) {
-
- FILE *f = fopen(fname, "w");
-
- char pline[1000];
-
- int plinelim;
-
- register row, col;
-
- register struct ent **p;
-
- if (f==0) {
-
- error ("Can't create %s", fname);
-
- return;
-
- }
-
- for (row=0;row<=maxrow; row++) {
-
- register c = 0;
-
- plinelim = 0;
-
- for (p = &tbl[row][col=0]; col<=maxcol; col++, p++) {
-
- if (*p) {
-
- char *s;
-
- while (plinelim<c) pline[plinelim++] = ' ';
-
- plinelim = c;
-
- if ((*p)->flags&is_valid) {
-
- sprintf (pline+plinelim,"%*.*f",fwidth[col],precision[col],
-
- (*p)->v);
-
- plinelim += strlen (pline+plinelim);
-
- }
-
- if (s = (*p)->label) {
-
- register char *d;
-
- d = pline+((*p)->flags&is_leftflush
-
- ? c : c-strlen(s)+fwidth[col]);
-
- while (d>pline+plinelim) pline[plinelim++] = ' ';
-
- if (d<pline) d = pline;
-
- while (*s) *d++ = *s++;
-
- if (d-pline>plinelim) plinelim = d-pline;
-
- }
-
- }
-
- c += fwidth [col];
-
- }
-
- fprintf (f,"%.*s\n",plinelim,pline);
-
- }
-
- fclose (f);
-
- }
-
-
-
- tblprintfile (fname) {
-
- FILE *f = fopen(fname, "w");
-
- char pline[1000];
-
- int plinelim;
-
- register row, col;
-
- register struct ent **p;
-
- char coldelim = DEFCOLDELIM;
-
-
-
- if (f==0) {
-
- error ("Can't create %s", fname);
-
- return;
-
- }
-
- for (row=0;row<=maxrow; row++) {
-
- register c = 0;
-
- plinelim = 0;
-
- for (p = &tbl[row][col=0]; col<=maxcol; col++, p++) {
-
- if (*p) {
-
- char *s;
-
- if ((*p)->flags&is_valid) {
-
- fprintf (f,"%.*f",precision[col],
-
- (*p)->v);
-
- }
-
- if (s = (*p)->label) {
-
- fprintf (f,"%s",s);
-
- }
-
- }
-
- fprintf(f,"%c",coldelim);
-
- }
-
- fprintf (f,"\n",pline);
-
- }
-
- fclose (f);
-
- }
-
-
-
- struct enode *copye (e, Rdelta, Cdelta)
-
- register struct enode *e; {
-
- register struct enode *ret;
-
- if (e==0) ret = 0;
-
- else {
-
- ret = (struct enode *) malloc (sizeof (struct enode));
-
- ret->op = e->op;
-
- switch (ret->op) {
-
- case 'v':
-
- ret->e.v = lookat (e->e.v->row+Rdelta, e->e.v->col+Cdelta);
-
- break;
-
- case 'k':
-
- ret->e.k = e->e.k;
-
- break;
-
- case 'f':
-
- ret->e.o.right = copye (e->e.o.right,0,0);
-
- ret->e.o.left = 0;
-
- break;
-
- case O_REDUCE('+'):
-
- case O_REDUCE('*'):
-
- case O_REDUCE('a'):
-
- ret->e.o.right = (struct enode *) lookat (
-
- ((struct ent *)e->e.o.right)->row+Rdelta,
-
- ((struct ent *)e->e.o.right)->col+Cdelta
-
- );
-
- ret->e.o.left = (struct enode *) lookat (
-
- ((struct ent *)e->e.o.left)->row+Rdelta,
-
- ((struct ent *)e->e.o.left)->col+Cdelta
-
- );
-
- break;
-
- default:
-
- ret->e.o.right = copye (e->e.o.right,Rdelta,Cdelta);
-
- ret->e.o.left = copye (e->e.o.left,Rdelta,Cdelta);
-
- break;
-
- }
-
- }
-
- return ret;
-
- }
-
-
-
- /*
-
- * sync_refs and sync_ref are used to remove references to
-
- * deleted struct ents. Note that the deleted structure must still
-
- * be hanging around before the call, but not referenced by an entry
-
- * in tbl. Thus the free_ent, fix_ent calls in sc.c
-
- */
-
-
-
- sync_refs () {
-
- register i,j;
-
- register struct ent *p;
-
- for (i=0; i<=maxrow; i++)
-
- for (j=0; j<=maxcol; j++)
-
- if ((p=tbl[i][j]) && p->expr)
-
- sync_ref(p->expr);
-
- }
-
-
-
-
-
- sync_ref(e)
-
- register struct enode *e;
-
- {
-
- if (e==0)
-
- return;
-
- else {
-
- switch (e->op) {
-
- case 'v':
-
- e->e.v = lookat(e->e.v->row, e->e.v->col);
-
- break;
-
- case 'k':
-
- break;
-
- case O_REDUCE('+'):
-
- case O_REDUCE('*'):
-
- case O_REDUCE('a'):
-
- e->e.o.right = (struct enode *) lookat (
-
- ((struct ent *)e->e.o.right)->row,
-
- ((struct ent *)e->e.o.right)->col
-
- );
-
- e->e.o.left = (struct enode *) lookat (
-
- ((struct ent *)e->e.o.left)->row,
-
- ((struct ent *)e->e.o.left)->col
-
- );
-
- break;
-
- default:
-
- sync_ref(e->e.o.right);
-
- sync_ref(e->e.o.left);
-
- break;
-
- }
-
- }
-
- }
-
-
-
- hiderow(arg)
-
- {
-
- register int r1;
-
- register int r2;
-
-
-
- r1 = currow;
-
- r2 = r1 + arg - 1;
-
- if (r1 < 0 || r1 > r2) {
-
- error("Invalid Range");
-
- return;
-
- }
-
- if (r2 > MAXROWS-2) {
-
- error("You can't hide the last row");
-
- return;
-
- }
-
- FullUpdate++;
-
- while (r1 <= r2)
-
- hidden_row[r1++] = 1;
-
- }
-
-
-
- hidecol(arg)
-
- {
-
- register int c1;
-
- register int c2;
-
-
-
- c1 = curcol;
-
- c2 = c1 + arg - 1;
-
- if (c1 < 0 || c1 > c2) {
-
- error("Invalid Range");
-
- return;
-
- }
-
- if (c2 > MAXCOLS-2) {
-
- error("You can't hide the last col");
-
- return;
-
- }
-
- FullUpdate++;
-
- while (c1 <= c2)
-
- hidden_col[c1++] = 1;
-
- }
-
-
-
- showrow(r1, r2)
-
- {
-
- if (r1 < 0 || r1 > r2) {
-
- error("Invalid Range");
-
- return;
-
- }
-
- if (r2 > MAXROWS-1) {
-
- r2 = MAXROWS-1;
-
- }
-
- FullUpdate++;
-
- while (r1 <= r2)
-
- hidden_row[r1++] = 0;
-
- }
-
-
-
- showcol(c1, c2)
-
- {
-
- if (c1 < 0 || c1 > c2) {
-
- error("Invalid Range");
-
- return;
-
- }
-
- if (c2 > MAXCOLS-1) {
-
- c2 = MAXCOLS-1;
-
- }
-
- FullUpdate++;
-
- while (c1 <= c2)
-
- hidden_col[c1++] = 0;
-
- }
-
-